#include "StdAfx.h"
#include "parse.h"
#include "global.h"
#include "util.h"
#include "scan.h"

parse::parse(void)
{
}

parse::~parse(void)
{
}

static _TokenType token; /* holds current token */

/* function prototypes for recursive calls */

static TreeNode * program(void);
static TreeNode * declarations(void);
static TreeNode * decl(void);
static TreeNode * varlist(_TokenType);

static TreeNode * stmt_sequence(void);
static TreeNode * statement(void);

static TreeNode * while_stmt(void);

static TreeNode * if_stmt(void);
static TreeNode * repeat_stmt(void);
static TreeNode * assign_stmt(void);
static TreeNode * read_stmt(void);
static TreeNode * write_stmt(void);
static TreeNode * exp(void);

static TreeNode * comparison_exp(void);
static TreeNode * arithmetic_exp(void);
static TreeNode * term(void);
static TreeNode * factor(void);
static TreeNode * bool_exp(void);
static TreeNode * bterm(void);
static TreeNode * bfactor(void);
static TreeNode * string_exp(void);




static void syntaxError(char * message)
{
	fprintf(global::listing,"\n>>> ");
	fprintf(global::listing,"Syntax error at line %d: %s",global::lineno,message);
	global::Error = TRUE;
}

static void match(_TokenType expected)
{ 
	if (token == expected) token = scan::getToken();
	else {
		syntaxError("unexpected token -> ");
		util::printToken(token,tokenString);
		fprintf(global::listing,"      ");
	}
}

TreeNode * program(void)
{
	TreeNode * s=util::newStmtNode(ProgramK);
	TreeNode * p=declarations();
	TreeNode * q=NULL;
	s->child[0]=p;
	if (token != ENDFILE)
		q=stmt_sequence();
	if(p!=NULL && q!=NULL)
	{
		s->child[1]=q;
	}
	if(p==NULL && q!=NULL) s->child[1] = q;
	return s;
}

TreeNode * declarations(void)
{
	TreeNode * t = NULL;
	TreeNode * p = NULL;
	TreeNode * q = NULL;
	if(token==_INT || token==_BOOL || token==_STRING)
		p=decl();
	if(p!=NULL){
		t=p;
		match(SEMI);
	}
	while(token==_INT || token==_BOOL || token==_STRING)
	{
		q = decl();
		match(SEMI);
		if(q!=NULL){
			p->sibling = q;
			p = q;
		}	
	}
	return t;
}

TreeNode * decl(void)
{
	TreeNode * t=util::newStmtNode(DeclK);
	switch(token)
	{
	case _INT:
		match(_INT);
		t->type=Integer;
		t->tok=_INT;
		break;
	case _BOOL:
		match(_BOOL);
		t->type=Boolean;
		t->tok=_BOOL;
		break;
	case _STRING:
		match(_STRING);
		t->type=String;
		t->tok=_STRING;
		break;
	default:
		syntaxError("unexpected token -> ");
		util::printToken(token,tokenString);
		token = scan::getToken();
		break;
	}
	t->child[0]=varlist(t->tok);	
	return t;
}


TreeNode * varlist(_TokenType op)
{
	TreeNode *t=util::newStmtNode(VarlistK);
	TreeNode *p=t;
	TreeNode *q=NULL;
	if(t!=NULL && token==ID)
	{
		t->tok=op;
		t->attr.name=util::copyString(tokenString);
		match(ID);
	}
	while(token==COMMA)
	{
		match(COMMA);
		q=util::newStmtNode(VarlistK);
		if(q!=NULL && token==ID)
		{
			q->attr.name=util::copyString(tokenString);
			q->tok=op;
			match(ID);
			p->sibling=q;
			p=q;
		}
	}
	return t;
}

TreeNode * stmt_sequence(void)
{ 
	TreeNode * t = statement();
	TreeNode * p = t;
	while ((token!=ENDFILE) && (token!=END) &&
		(token!=ELSE) && (token!=UNTIL))
	{ 
		TreeNode * q;
		match(SEMI);
		q = statement();
		if (q!=NULL) {
			if (t==NULL) 
				t = p = q;
			else /* now p cannot be NULL either */
			{ 
				p->sibling = q;
				p = q;
			}
		}
	}
return t;
}

TreeNode * statement(void)
{
	TreeNode * t=NULL;
	if (token != ENDFILE) {
	switch (token) {
	case IF : t = if_stmt(); break;
	case REPEAT : t = repeat_stmt(); break;
	case ID : t = assign_stmt(); break;
	case READ : t = read_stmt(); break;
	case WRITE : t = write_stmt(); break;
	case WHILE : t = while_stmt(); break;
	case END: break;
	case ELSE: break;
	default : syntaxError("unexpected token -> ");
		util::printToken(token,tokenString);
		token = scan::getToken();
		break;
	} /* end case */
	}
	return t;
}

TreeNode * if_stmt(void)
{ 
	TreeNode * t = util::newStmtNode(IfK);
	match(IF);
	if (t!=NULL) t->child[0] = bool_exp();
	match(THEN);
	if (t!=NULL) t->child[1] = stmt_sequence();
	if (token==ELSE) {
		match(ELSE);
		if (t!=NULL) t->child[2] = stmt_sequence();
	}
	match(END);
	return t;
}

TreeNode * repeat_stmt(void)
{ 
	TreeNode * t = util::newStmtNode(RepeatK);
	match(REPEAT);
	if (t!=NULL) t->child[0] = stmt_sequence();
	match(UNTIL);
	if (t!=NULL) t->child[1] = bool_exp();
	return t;
}

TreeNode * assign_stmt(void)
{
	TreeNode * t = util::newStmtNode(AssignK);
	if ((t!=NULL) && (token==ID))
		t->attr.name = util::copyString(tokenString);
	match(ID);
	match(ASSIGN);
	if (t!=NULL) t->child[0] = exp();
	return t;
}

TreeNode * read_stmt(void)
{
	TreeNode * t = util::newStmtNode(ReadK);
	match(READ);
	if ((t!=NULL) && (token==ID))
		t->attr.name = util::copyString(tokenString);
	match(ID);
	return t;
}

TreeNode * write_stmt(void)
{ 
	TreeNode * t = util::newStmtNode(WriteK);
	match(WRITE);
	if (t!=NULL) t->child[0] = exp();
	return t;
}

TreeNode * while_stmt(void)
{
	TreeNode * t = util::newStmtNode(WhileK);
	match(WHILE);
	if (t!=NULL) t->child[0] = bool_exp();
	match(DO);
	if (t!=NULL) t->child[1] = stmt_sequence();
	match(END);
	return t;
}

TreeNode * exp(void)
{
	TreeNode * t=NULL;
	switch(token)
	{
	case ID:
	case NUM:
	case LPAREN:
	case _TRUE:
	case _FALSE:
	case NOT:
		t=bool_exp();
		break;
	case STR:
		t=string_exp();
	default:
		break;
	}
	return t;
}

TreeNode * arithmetic_exp(void)
{
	TreeNode *t = term();
	while((token==PLUS) || (token==MINUS))
	{
		TreeNode *p = util::newExpNode(OpK);
		if(p!=NULL)
		{
			p->child[0]=t;
			p->attr.op=token;
			t=p;
			match(token);		
			p->child[1]=term();		
		}			
	}
	return t;
}

TreeNode * not_exp(void)
{
	TreeNode * t=NULL;
	switch(token)
	{
	case NOT:
		match(NOT);
		t=exp();
		break;
	case _TRUE:
	case _FALSE:
		match(token);
		break;
	case LPAREN:
	case ID:
	case NUM:
		t=comparison_exp();
		break;
	default:
		syntaxError("unexpected token -> ");
		util::printToken(token,tokenString);
		token = scan::getToken();
		break;
	}
	return t;
}


TreeNode * bfactor(void)
{
	TreeNode * t=not_exp();
	TreeNode * p=t;
	while(t!=NULL && (token==AND))
	{
		TreeNode * q=NULL;
		p=util::newExpNode(OpK);
		p->attr.op=token;
		match(AND);
		p->child[0]=t;
		t=p;
		q=not_exp();		
		if(q!=NULL)
		{
			t->child[1]=q;
		}
	}
	return t;
}

TreeNode * bterm(void)
{
	TreeNode * t=bfactor();
	TreeNode * p=t;
	while(t!=NULL && (token==OR))
	{
		TreeNode * q=NULL;
		p=util::newExpNode(OpK);
		p->attr.op=token;
		match(OR);
		p->child[0]=t;
		t=p;
		q=bfactor();		
		if(q!=NULL)
		{
			t->child[1]=q;
		}
	}
	return t;
}

TreeNode * bool_exp(void)
{
	TreeNode * t=bterm();
	return t;
}

TreeNode * comparison_exp(void)
{
	TreeNode * t=arithmetic_exp();
	if(token==LT || token==GT || token==EQ || token==GET || token==LET )
	{
		TreeNode *p=util::newExpNode(OpK);
		if(p!=NULL)
		{
			p->child[0]=t;
			p->attr.op=token;
			t=p;
			match(token);
			if(t!=NULL)
			t->child[1]=arithmetic_exp();
		}
	}
	return t;
}

TreeNode * string_exp(void)
{
	TreeNode * t= util::newExpNode(StringK);
	if(t!=NULL)
	{
		int n = strlen(tokenString)+1;
		t->attr.name = new char(n);
		t->attr.name=util::copyString(tokenString);
		t->type=String;
		match(STR);
	}
	return t;
}

TreeNode * term(void)
{ 
	TreeNode * t = factor();
	while ((token==TIMES)||(token==OVER))
	{
		TreeNode * p = util::newExpNode(OpK);
		if (p!=NULL) {
			p->child[0] = t;
			p->attr.op = token;
			t = p;
			match(token);
			p->child[1] = factor();
		}
	}
	return t;
}

TreeNode * factor(void)
{
	TreeNode * t = NULL;
	switch (token) {
	case NUM :
		t = util::newExpNode(ConstK);
		if ((t!=NULL) && (token==NUM))
			t->attr.val = atoi(tokenString);
		match(NUM);
		break;
	case ID :
		t = util::newExpNode(IdK);
		if ((t!=NULL) && (token==ID))
			t->attr.name = util::copyString(tokenString);
		match(ID);
		break;
	case LPAREN :
		match(LPAREN);
		t = exp();
		match(RPAREN);
		break;
	default:
		syntaxError("unexpected token -> ");
		util::printToken(token,tokenString);
		token = scan::getToken();
		break;
	}
	return t;
}

/****************************************/
/* the primary function of the parser   */
/****************************************/
/* Function parse returns the newly 
* constructed syntax tree
*/
TreeNode * parse::parseCode(void)
{ 
//	global::lineno = 0;
	scan::reset();
	TreeNode * t;
	token = scan::getToken();
	t = program();
	if (token!=ENDFILE)
		syntaxError("Code ends before file\n");
	return t;
}
